package org.light.domain;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.light.core.Writeable;
import org.light.exception.ValidateException;
import org.light.generator.UtilMethodsGenerator;
import org.light.utils.DomainUtil;
import org.light.utils.StringUtil;
import org.light.utils.WriteableUtil;

public class DummyDaoImpl extends DaoImpl {
	private static final long serialVersionUID = -7376733796370937661L;

	@Override
	public String generateDaoImplString() throws ValidateException{
		if (this.domain instanceof org.light.domain.Enum) {
			if ("datadummy".equalsIgnoreCase(this.domain.getSchema())) {
				return generateEnumDummyDaoImplForDataDummySchemaStatements().getContent();
			} else {
				return generateEnumDummyDaoImplStatements().getContent();
			}
		}else {
			return generateDummyDaoImplStatements().getContent();
		}
	}	

	public StatementList generateDummyDaoImplStatements() throws ValidateException{
		this.methods.add(UtilMethodsGenerator.generateInitDbMethod(domain));
		this.methods.add(UtilMethodsGenerator.generateMaxIdMethod(domain));
		
		List<Writeable> sList = new ArrayList<Writeable>();
		this.addClassImports("org.springframework.stereotype.Repository");
		this.addClassImports(this.domain.getPackageToken() + "." + this.domain.getDaoSuffix() + "."
				+ this.domain.getStandardName() + "Dao");
		this.addClassImports(this.domain.getPackageToken() + "." + this.domain.getDomainSuffix() + "."
				+ this.domain.getCapFirstDomainNameWithSuffix());
		if (this.packageToken !=null && !"".equalsIgnoreCase(this.packageToken)) sList.add(new Statement(1000L,0,"package "+this.packageToken+"."+this.domain.getDaoimplSuffix()+";"));
		sList.add(new Statement(2000L,0,""));
		long serial = 3000L;
		Set<String> imports = this.generateImportStrings();
		for (String s: imports){
			sList.add(new Statement(serial,0,"import "+s+";"));
			serial += 1000L;
		}
		sList.add(new Statement(serial,0,""));
		
		for (ManyToMany mtm:this.domain.getManyToManies()) {
			sList.add(new Statement(serial+1000L,0,"class Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+" implements Comparable<Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"> {"));
			sList.add(new Statement(serial+2000L,1,"protected Long "+mtm.getMaster().getLowerFirstDomainName()+"Id;"));
			sList.add(new Statement(serial+3000L,1,"protected Long "+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id;"));
			sList.add(new Statement(serial+4000L,0,""));
			sList.add(new Statement(serial+5000L,1,"@Override"));
			sList.add(new Statement(serial+6000L,1,"public int compareTo(Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+" o) {"));
			sList.add(new Statement(serial+7000L,2,"if (o.get"+mtm.getMaster().getCapFirstDomainName()+"Id().equals(this.get"+mtm.getMaster().getCapFirstDomainName()+"Id()) && o.get"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id().equals(this.get"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id())) return 0;"));
			sList.add(new Statement(serial+8000L,2,"else return -1;"));
			sList.add(new Statement(serial+9000L,1,"}"));
			sList.add(new Statement(serial+10000L,0,""));
			sList.add(new Statement(serial+11000L,1,"public Long get"+mtm.getMaster().getCapFirstDomainName()+"Id() {"));
			sList.add(new Statement(serial+12000L,2,"return "+mtm.getMaster().getLowerFirstDomainName()+"Id;"));
			sList.add(new Statement(serial+13000L,1,"}"));
			sList.add(new Statement(serial+14000L,0,""));
			sList.add(new Statement(serial+15000L,1,"public void set"+mtm.getMaster().getCapFirstDomainName()+"Id(Long "+mtm.getMaster().getLowerFirstDomainName()+"Id) {"));
			sList.add(new Statement(serial+16000L,2,"this."+mtm.getMaster().getLowerFirstDomainName()+"Id = "+mtm.getMaster().getLowerFirstDomainName()+"Id;"));
			sList.add(new Statement(serial+17000L,1,"}"));
			sList.add(new Statement(serial+18000L,0,""));
			sList.add(new Statement(serial+19000L,1,"public Long get"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id() {"));
			sList.add(new Statement(serial+20000L,2,"return "+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id;"));
			sList.add(new Statement(serial+21000L,1,"}"));
			sList.add(new Statement(serial+22000L,0,""));
			sList.add(new Statement(serial+23000L,1,"public void set"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id(Long "+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id) {"));
			sList.add(new Statement(serial+24000L,2,"this."+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id = "+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id;"));
			sList.add(new Statement(serial+25000L,1,"}"));
			sList.add(new Statement(serial+26000L,0,"}"));
			sList.add(new Statement(serial+27000L,0,""));
			serial += 28000L;
		}		
		
		sList.add(new Statement(serial,0,"@Repository"));
		StringBuilder sb = new StringBuilder("");
		sb.append("public class ").append(StringUtil.capFirst(this.getDomain().getStandardName())).append("DummyDaoImpl");
		if (extendedType != null) sb.append(" extends ").append(extendedType.getTypeName());
		sb.append(" implements ").append(StringUtil.capFirst(this.getDomain().getStandardName())).append("Dao").append("{");
		sList.add(new Statement(serial+1000L,0,sb.toString()));
		
		sList.add(new Statement(serial+2000L,1,"public static List<"+this.domain.getCapFirstDomainNameWithSuffix()+"> db = initDb();"));
		serial += 3000L;
		for (ManyToMany mtm:this.domain.getManyToManies()) {
			sList.add(new Statement(serial,1,"public static List<Link"+mtm.getMaster().getCapFirstDomainName()+""+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"> "+mtm.getMaster().getLowerFirstDomainName()+""+StringUtil.capFirst(mtm.getSlaveAlias())+"LinkDb = init"+mtm.getMaster().getCapFirstDomainName()+""+StringUtil.capFirst(mtm.getSlaveAlias())+"LinkDb();"));
			serial += 1000L;
		}
		
		for (ManyToMany mtm:this.domain.getManyToManies()) {
			sList.add(new Statement(serial,1,"protected static List<Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"> init"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+"LinkDb() {"));
			sList.add(new Statement(serial+1000L,2,"List<Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"> _db = new ArrayList<>();"));
			List<ManyToMany> dataMtms = DomainUtil.filterMtms(this.domain.getDummyDb(),mtm);
			int dmtmSerial = 1;
			for (ManyToMany dmtm: dataMtms) {				
				for (String slaveValue:dmtm.getSlaveValuesList()) {
					sList.add(new Statement(serial+1000L,2,"Link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+" link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+dmtmSerial+" = new Link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"();"));
					sList.add(new Statement(serial+2000L,2,"link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+dmtmSerial+".set"+dmtm.getMaster().getCapFirstDomainName()+"Id("+dmtm.getMasterValue()+"L);"));
					sList.add(new Statement(serial+3000L,2,"link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+dmtmSerial+".set"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id("+slaveValue+"L);"));
					sList.add(new Statement(serial+4000L,2,"_db.add(link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+dmtmSerial+");"));
					serial += 5000L;
					dmtmSerial ++;					
				}
			}
			sList.add(new Statement(serial+2000L,2,"return _db;"));
			sList.add(new Statement(serial+3000L,1,"}"));
			sList.add(new Statement(serial+4000L,2,""));
			serial += 5000L;
		}
		
		Iterator it = this.fields.iterator();
		while(it.hasNext()){
			Field f = (Field)it.next();
			sList.add(new Statement(serial+1000L,1,"public "+f.getFieldType()+" "+f.getFieldName()+";"));
		}

		Iterator it2 = this.methods.iterator();
		while(it2.hasNext()){
			Method m = (Method)it2.next();
			sList.add(m.generateMethodFullStatements(serial, 0));
			sList.add(new Statement(serial+1000L,0,""));
			serial += 2000L;
		}
		sList.add(new Statement(serial,0,"}"));
		return WriteableUtil.merge(sList);
	}
	
	public StatementList generateEnumDummyDaoImplStatements() throws ValidateException{
		if (this.domain.getDbType().equalsIgnoreCase("oracle")) {
			this.methods.add(UtilMethodsGenerator.generateInitOracleDbMethod(domain));
		} else {
			this.methods.add(UtilMethodsGenerator.generateInitDbMethod(domain));
		}

		List<Writeable> sList = new ArrayList<Writeable>();
		this.addClassImports("org.springframework.stereotype.Repository");
		this.addClassImports(this.domain.getPackageToken() + "." + this.domain.getDaoSuffix() + "."
				+ this.domain.getStandardName() + "Dao");
		this.addClassImports(this.domain.getPackageToken() + "." + this.domain.getDomainSuffix() + "."
				+ this.domain.getCapFirstDomainNameWithSuffix());
		if (this.packageToken !=null && !"".equalsIgnoreCase(this.packageToken)) sList.add(new Statement(1000L,0,"package "+this.packageToken+"."+this.domain.getDaoimplSuffix()+";"));
		sList.add(new Statement(2000L,0,""));
		long serial = 3000L;
		Set<String> imports = this.generateImportStrings();
		for (String s: imports){
			sList.add(new Statement(serial,0,"import "+s+";"));
			serial += 1000L;
		}
		sList.add(new Statement(serial,0,""));
			
		sList.add(new Statement(serial,0,"@Repository(\""+this.domain.getLowerFirstDomainName()+"DummyDaoImpl\")"));
		StringBuilder sb = new StringBuilder("");
		sb.append("public class ").append(StringUtil.capFirst(this.getDomain().getStandardName())).append("DummyDaoImpl");
		if (extendedType != null) sb.append(" extends ").append(extendedType.getTypeName());
		sb.append(" implements ").append(StringUtil.capFirst(this.getDomain().getStandardName())).append("Dao").append("{");
		sList.add(new Statement(serial+1000L,0,sb.toString()));
		
		sList.add(new Statement(serial+2000L,1,"public static List<"+this.domain.getCapFirstDomainNameWithSuffix()+"> db = initDb();"));
		serial += 3000L;
		
		Iterator it = this.fields.iterator();
		while(it.hasNext()){
			Field f = (Field)it.next();
			sList.add(new Statement(serial+1000L,1,"public "+f.getFieldType()+" "+f.getFieldName()+";"));
		}

		Iterator it2 = this.methods.iterator();
		while(it2.hasNext()){
			Method m = (Method)it2.next();
			sList.add(m.generateMethodFullStatements(serial, 0));
			sList.add(new Statement(serial+1000L,0,""));
			serial += 2000L;
		}
		sList.add(new Statement(serial,0,"}"));
		return WriteableUtil.merge(sList);
	}
	
	public StatementList generateEnumDummyDaoImplForDataDummySchemaStatements() throws ValidateException{
		this.methods.add(UtilMethodsGenerator.generateInitDbMethod(domain));

		List<Writeable> sList = new ArrayList<Writeable>();
		this.addClassImports("org.springframework.stereotype.Repository");
		this.addClassImports(this.domain.getPackageToken() + "." + this.domain.getDaoSuffix() + "."
				+ this.domain.getStandardName() + "Dao");
		this.addClassImports(this.domain.getPackageToken() + "." + this.domain.getDomainSuffix() + "."
				+ this.domain.getCapFirstDomainNameWithSuffix());
		if (this.packageToken !=null && !"".equalsIgnoreCase(this.packageToken)) sList.add(new Statement(1000L,0,"package "+this.packageToken+"."+this.domain.getDaoimplSuffix()+";"));
		sList.add(new Statement(2000L,0,""));
		long serial = 3000L;
		Set<String> imports = this.generateImportStrings();
		for (String s: imports){
			sList.add(new Statement(serial,0,"import "+s+";"));
			serial += 1000L;
		}
		sList.add(new Statement(serial,0,""));
		
		for (ManyToMany mtm:this.domain.getManyToManies()) {
			sList.add(new Statement(serial+1000L,0,"class Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+" implements Comparable<Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"> {"));
			sList.add(new Statement(serial+2000L,1,"protected Long "+mtm.getMaster().getLowerFirstDomainName()+"Id;"));
			sList.add(new Statement(serial+3000L,1,"protected Long "+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id;"));
			sList.add(new Statement(serial+4000L,0,""));
			sList.add(new Statement(serial+5000L,1,"@Override"));
			sList.add(new Statement(serial+6000L,1,"public int compareTo(Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+" o) {"));
			sList.add(new Statement(serial+7000L,2,"if (o.get"+mtm.getMaster().getCapFirstDomainName()+"Id().equals(this.get"+mtm.getMaster().getCapFirstDomainName()+"Id()) && o.get"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id().equals(this.get"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id())) return 0;"));
			sList.add(new Statement(serial+8000L,2,"else return -1;"));
			sList.add(new Statement(serial+9000L,1,"}"));
			sList.add(new Statement(serial+10000L,0,""));
			sList.add(new Statement(serial+11000L,1,"public Long get"+mtm.getMaster().getCapFirstDomainName()+"Id() {"));
			sList.add(new Statement(serial+12000L,2,"return "+mtm.getMaster().getLowerFirstDomainName()+"Id;"));
			sList.add(new Statement(serial+13000L,1,"}"));
			sList.add(new Statement(serial+14000L,0,""));
			sList.add(new Statement(serial+15000L,1,"public void set"+mtm.getMaster().getCapFirstDomainName()+"Id(Long "+mtm.getMaster().getLowerFirstDomainName()+"Id) {"));
			sList.add(new Statement(serial+16000L,2,"this."+mtm.getMaster().getLowerFirstDomainName()+"Id = "+mtm.getMaster().getLowerFirstDomainName()+"Id;"));
			sList.add(new Statement(serial+17000L,1,"}"));
			sList.add(new Statement(serial+18000L,0,""));
			sList.add(new Statement(serial+19000L,1,"public Long get"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id() {"));
			sList.add(new Statement(serial+20000L,2,"return "+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id;"));
			sList.add(new Statement(serial+21000L,1,"}"));
			sList.add(new Statement(serial+22000L,0,""));
			sList.add(new Statement(serial+23000L,1,"public void set"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id(Long "+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id) {"));
			sList.add(new Statement(serial+24000L,2,"this."+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id = "+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id;"));
			sList.add(new Statement(serial+25000L,1,"}"));
			sList.add(new Statement(serial+26000L,0,"}"));
			sList.add(new Statement(serial+27000L,0,""));
			serial += 28000L;
		}
			
		sList.add(new Statement(serial,0,"@Repository(\""+this.domain.getLowerFirstDomainName()+"DummyDaoImpl\")"));
		StringBuilder sb = new StringBuilder("");
		sb.append("public class ").append(StringUtil.capFirst(this.getDomain().getStandardName())).append("DummyDaoImpl");
		if (extendedType != null) sb.append(" extends ").append(extendedType.getTypeName());
		sb.append(" implements ").append(StringUtil.capFirst(this.getDomain().getStandardName())).append("Dao").append("{");
		sList.add(new Statement(serial+1000L,0,sb.toString()));
		
		sList.add(new Statement(serial+2000L,1,"public static List<"+this.domain.getCapFirstDomainNameWithSuffix()+"> db = initDb();"));
		serial += 3000L;
		
		for (ManyToMany mtm:this.domain.getManyToManies()) {
			sList.add(new Statement(serial,1,"public static List<Link"+mtm.getMaster().getCapFirstDomainName()+""+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"> "+mtm.getMaster().getLowerFirstDomainName()+""+StringUtil.capFirst(mtm.getSlaveAlias())+"LinkDb = init"+mtm.getMaster().getCapFirstDomainName()+""+StringUtil.capFirst(mtm.getSlaveAlias())+"LinkDb();"));
			serial += 1000L;
		}
		
		for (ManyToMany mtm:this.domain.getManyToManies()) {
			sList.add(new Statement(serial,1,"protected static List<Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"> init"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+"LinkDb() {"));
			sList.add(new Statement(serial+1000L,2,"List<Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"> _db = new ArrayList<>();"));
			List<ManyToMany> dataMtms = DomainUtil.filterMtms(this.domain.getDummyDb(),mtm);
			int dmtmSerial = 1;
			for (ManyToMany dmtm: dataMtms) {				
				for (String slaveValue:dmtm.getSlaveValuesList()) {
					sList.add(new Statement(serial+1000L,2,"Link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+" link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+dmtmSerial+" = new Link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"();"));
					sList.add(new Statement(serial+2000L,2,"link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+dmtmSerial+".set"+dmtm.getMaster().getCapFirstDomainName()+"Id("+dmtm.getMasterValue()+"L);"));
					sList.add(new Statement(serial+3000L,2,"link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+dmtmSerial+".set"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id("+slaveValue+"L);"));
					sList.add(new Statement(serial+4000L,2,"_db.add(link"+dmtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+dmtmSerial+");"));
					serial += 5000L;
					dmtmSerial ++;					
				}
			}
			sList.add(new Statement(serial+2000L,2,"return _db;"));
			sList.add(new Statement(serial+3000L,1,"}"));
			sList.add(new Statement(serial+4000L,2,""));
			serial += 5000L;
		}
		
		Iterator it = this.fields.iterator();
		while(it.hasNext()){
			Field f = (Field)it.next();
			sList.add(new Statement(serial+1000L,1,"public "+f.getFieldType()+" "+f.getFieldName()+";"));
		}

		Iterator it2 = this.methods.iterator();
		while(it2.hasNext()){
			Method m = (Method)it2.next();
			sList.add(m.generateMethodFullStatements(serial, 0));
			sList.add(new Statement(serial+1000L,0,""));
			serial += 2000L;
		}
		sList.add(new Statement(serial,0,"}"));
		return WriteableUtil.merge(sList);
	}
}
